package com.zijidelu.luframework.utils.lang.reflect;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * 类型兼容性工具类
 * 用于判断两个类型在Java自动拆装箱、数字宽化转换等场景下的兼容性。
 * @author ZIJIDELU
 * @datetime 2025-11-24 10:00:00
 */
public class TypeCompatibilityUtils {
    
    /**
     * 基本类型与包装类型的映射表
     * 使用 Map.ofEntries 以支持超过10个键值对的初始化
     */
    private static final Map<Class<?>, Class<?>> PRIMITIVE_TO_WRAPPER = Map.ofEntries(
        Map.entry(byte.class, Byte.class),
        Map.entry(short.class, Short.class),
        Map.entry(int.class, Integer.class),
        Map.entry(long.class, Long.class),
        Map.entry(float.class, Float.class),
        Map.entry(double.class, Double.class),
        Map.entry(boolean.class, Boolean.class),
        Map.entry(char.class, Character.class),
        Map.entry(void.class, Void.class)
    );
    
    /**
     * 包装类型与基本类型的映射表
     */
    private static final Map<Class<?>, Class<?>> WRAPPER_TO_PRIMITIVE = Map.ofEntries(
        Map.entry(Byte.class, byte.class),
        Map.entry(Short.class, short.class),
        Map.entry(Integer.class, int.class),
        Map.entry(Long.class, long.class),
        Map.entry(Float.class, float.class),
        Map.entry(Double.class, double.class),
        Map.entry(Boolean.class, boolean.class),
        Map.entry(Character.class, char.class),
        Map.entry(Void.class, void.class)
    );
    
    /**
     * 所有兼容的类型对（基本类型与包装类型）
     * 优化：移除了自兼容配对，因为主方法已处理
     */
    private static final Set<TypePair> COMPATIBLE_TYPE_PAIRS = createCompatibleTypePairs();
    
    private static Set<TypePair> createCompatibleTypePairs() {
        Set<TypePair> pairs = new HashSet<>();
        for (Map.Entry<Class<?>, Class<?>> entry : PRIMITIVE_TO_WRAPPER.entrySet()) {
            pairs.add(new TypePair(entry.getKey(), entry.getValue()));
            pairs.add(new TypePair(entry.getValue(), entry.getKey()));
        }
        return pairs;
    }
    
    /**
     * 判断两个类型是否兼容，考虑自动拆装箱、数字宽化转换和继承关系。
     *
     * @param sourceType 源类型
     * @param targetType 目标类型
     * @return 如果兼容则返回 true，否则返回 false
     */
    public static boolean isAutoBoxingCompatible(Class<?> sourceType, Class<?> targetType) {
        if (sourceType == null || targetType == null) {
            return false;
        }
        
        // 1. 类型完全相同，直接放行
        if (sourceType == targetType) {
            return true;
        }
        
        // 2. 检查是否是基本类型和包装类型的关系
        if (isPrimitiveWrapperPair(sourceType, targetType)) {
            return true;
        }
        
        // 3. 检查数字类型之间的宽化转换（已修复 char 类型问题）
        if (isNumericWideningCompatible(sourceType, targetType)) {
            return true;
        }
        
        // 4. 检查继承关系
        if (targetType.isAssignableFrom(sourceType)) {
            return true;
        }

        return false;
    }
    
    /**
     * 判断是否是基本类型和对应的包装类型（双向）。
     */
    public static boolean isPrimitiveWrapperPair(Class<?> type1, Class<?> type2) {
        return COMPATIBLE_TYPE_PAIRS.contains(new TypePair(type1, type2));
    }
    
    /**
     * 判断数字类型之间的宽化转换兼容性（如 int → long, char → int）。
     * 修复：已加入 char 类型并调整了宽化顺序。
     */
    public static boolean isNumericWideningCompatible(Class<?> sourceType, Class<?> targetType) {
        // 数字类型的宽化转换顺序
        Map<Class<?>, Integer> numericOrder = Map.ofEntries(
            Map.entry(byte.class, 1), Map.entry(Byte.class, 1),
            Map.entry(short.class, 2), Map.entry(Short.class, 2),
            Map.entry(char.class, 3), Map.entry(Character.class, 3),
            Map.entry(int.class, 4), Map.entry(Integer.class, 4),
            Map.entry(long.class, 5), Map.entry(Long.class, 5),
            Map.entry(float.class, 6), Map.entry(Float.class, 6),
            Map.entry(double.class, 7), Map.entry(Double.class, 7)
        );
        
        Integer sourceOrder = numericOrder.get(sourceType);
        Integer targetOrder = numericOrder.get(targetType);
        
        // 如果都是数字类型，且目标类型比源类型"宽"
        return sourceOrder != null && targetOrder != null && targetOrder >= sourceOrder;
    }
    
    /**
     * 获取对应的包装类型（如果是基本类型）。
     */
    public static Class<?> getWrapperType(Class<?> type) {
        if (type.isPrimitive()) {
            return PRIMITIVE_TO_WRAPPER.get(type);
        }
        return type;
    }
    
    /**
     * 获取对应的基本类型（如果是包装类型）。
     */
    public static Class<?> getPrimitiveType(Class<?> type) {
        Class<?> primitive = WRAPPER_TO_PRIMITIVE.get(type);
        return primitive != null ? primitive : type;
    }
    
    /**
     * 规范化类型（将基本类型转换为对应的包装类型）。
     */
    public static Class<?> normalizeType(Class<?> type) {
        return getWrapperType(type);
    }
    
    /**
     * 使用规范化类型进行比较。
     * 注意：此方法不检查宽化转换，仅检查基本/包装类型的等价性。
     */
    public static boolean isNormalizedCompatible(Class<?> sourceType, Class<?> targetType) {
        return normalizeType(sourceType) == normalizeType(targetType);
    }
    
    /**
     * 类型对记录类，用于在Set中进行无序比较。
     * 优化：hashCode 方法使用异或操作以减少哈希冲突。
     */
    private record TypePair(Class<?> type1, Class<?> type2) {
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            TypePair typePair = (TypePair) o;
            return (type1 == typePair.type1 && type2 == typePair.type2) ||
                   (type1 == typePair.type2 && type2 == typePair.type1);
        }
        
        @Override
        public int hashCode() {
            // 使用异或操作组合哈希码，减少冲突，提高性能
            return type1.hashCode() ^ type2.hashCode();
        }
    }
}
